package com.crazy.practice.boot.core;

import com.crazy.entity.CommonResponse;
import com.crazy.exception.CrException;
import com.crazy.exception.ValidationException;
import com.crazy.util.ApplicationHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.core.annotation.Order;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Locale;
import java.util.stream.Stream;

/**
 * @author panyonghui
 * @describe 全局异常处理
 * @date 2022/1/17 11:38
 */
@Order(1)
@Slf4j
@RestControllerAdvice
public class ExceptionProcess {

    @Value("${response.error.message.key}")
    private String defaultMessageKey;

    @Autowired
    @Qualifier("messageSource")
    private MessageSource messageSource;

    @ExceptionHandler(value = Exception.class)
    public CommonResponse unknownError(Exception e){
        return formatMessage(e);
    }

    @ExceptionHandler(value = CrException.class)
    public CommonResponse crException(CrException e){
        return formatMessage(e);
    }

    @ExceptionHandler(value = ValidationException.class)
    public CommonResponse validationException(ValidationException e){
        return formatMessage(e);
    }

    /**
     * @describe 消息格式化
     * @auther crazy_cat
     * @date 2022/1/20 20:11
     * @param e
     * @return com.crazy.entity.CommonResponse
     * @modify
     */
    private CommonResponse formatMessage(Exception e){
        CommonResponse response = new CommonResponse();
        String messageKey;
        String message;
        Object[] args = new Object[0];
        if (e instanceof CrException) {
            CrException crException = (CrException)e;
            messageKey = crException.getMessageKey();
            message = crException.getDefaultMessage();
            args = crException.getArgs();
            // 描述为空，根据错误码获取错误描述
            if (StringUtils.isEmpty(message)) {
                if (args != null){
                    // 把参数的字段翻译成对应的参数
                    args = Stream.of(args).map(key -> {
                        try {
                            return messageSource.getMessage((String) key, null, Locale.getDefault());
                        } catch (NoSuchMessageException nsme){
                            // 未找到key值对应的参数
                            log.debug("未找到字段对应的参数:{}", key);
                            return key;
                        }
                    }).toArray();
                }
                try {
                    message = messageSource.getMessage(messageKey, args, Locale.getDefault());
                } catch (Exception e1){
                    // 未找到配置信息
                    log.debug("未找到错误码对应的参数,key:{}", messageKey);
                    message = messageSource.getMessage(defaultMessageKey, args, Locale.getDefault());
                }
            }
        } else {
            // 未知异常使用默认错误信息
            messageKey = defaultMessageKey;
//            message = messageSource.getMessage(DEFAULT_MESSAGE_KEY, args, Locale.getDefault());
            // 使用application工具类获取消息
            message = ApplicationHelper.getMessage(defaultMessageKey, args);
        }
        response.setResCode(messageKey);
        response.setResMsg(message);
        log.error("{} args:{}",messageKey, args , e);
        return response;
    }
}
